---
title: About ECDSA registry signatures
---

Packages published to the public npm registry are signed to make it possible to detect if the package content has been tampered with.

Signing and verifying published packages protects against an attacker controlling a registry mirror or proxy where they attempt to intercept and tamper with the package tarball content.

## Migrating from PGP to ECDSA signatures

<Note>

**Note:** PGP-based registry signatures were deprecated on **April 25th 2023** and replaced by ECDSA registry signatures.

</Note>

The public npm registry is migrating away from the existing PGP signatures to ECDSA signatures that are more compact and can be verified without extra dependencies in the npm CLI.

Signature verification was previously a multi-step process involving the Keybase CLI, as well as manually retrieving and parsing the signature from the package metadata.

Read more about [migrating and verifying signatures](/verifying-registry-signatures) using the npm CLI.

## Supporting signatures on third-party registries

The npm CLI supports registry signatures and signing keys provided by any registry if the following conventions are followed:

**1. Signatures are provided in the package's `packument` in each published version within the `dist` object:**

```
"dist":{
  ..omitted..,
  "signatures": [{
    "keyid": "SHA256:{{SHA256_PUBLIC_KEY}}",
    "sig": "a312b9c3cb4a1b693e8ebac5ee1ca9cc01f2661c14391917dcb111517f72370809..."
  }],
```

See this [example of a signed package from the public npm registry](https://registry.npmjs.org/light-cycle/1.4.3).

To generate the signature, sign the package name, version and tarball sha integrity: `${package.name}@${package.version}:${package.dist.integrity}`.

The current best practice is to use a [Key Management System](https://en.wikipedia.org/wiki/Key_management#Key_management_system) that does the signing operation on a [Hardware Security Module (HSM)](https://en.wikipedia.org/wiki/Hardware_security_module) in order to not directly handle the private key part, which reduces the attack surface.

The `keyid` must match one of the public signing keys below.

**2. Public signing keys are provided at `registry-host.tld/-/npm/v1/keys` in the following format:**

```
{
  "keys": [{
    "expires": null,
    "keyid": "SHA256:{{SHA256_PUBLIC_KEY}}",
    "keytype": "ecdsa-sha2-nistp256",
    "scheme": "ecdsa-sha2-nistp256",
    "key": "{{B64_PUBLIC_KEY}}"
  }]
}
```

Keys response:

- `expires`: null or a simplified extended [ISO 8601 format](https://en.wikipedia.org/wiki/ISO_8601): `YYYY-MM-DDTHH:mm:ss.sssZ`
- `keyid`: sha256 fingerprint of the public key
- `keytype`: only `ecdsa-sha2-nistp256` is currently supported by the npm CLI
- `scheme`: only `ecdsa-sha2-nistp256` is currently supported by the npm CLI
- `key`: base64 encoded public key

See this [example key's response from the public npm registry](https://registry.npmjs.org/-/npm/v1/keys).
